/*
 * Copyright 2008 Max Kugland
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.splink.library.logging.logoutput {
	import org.splink.library.logging.LogEvent;
	import org.splink.library.logging.LogLevel;

	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.XMLSocket;
	import flash.utils.Timer;	

	/**
	 * Sends log messages to the Quui Logging Server 
	 * 
	 * @author Max Kugland
	 */
	public class QLogOutput extends LogOutput {
		private var _socket : XMLSocket;
		private var _ip : String;
		private var _port : uint;
		private var _keepConnecting : Boolean;
		private var _timer : Timer;
		private var _treeAr : Array = new Array;

		/**
		 * @param ip the ip of the computer on which QLog runs
		 * @param port the port to connect on the computer running QLog
		 * @param keepConnecting setting keepConnecting to true means that <code>QLogOutput</code>
		 * keeps attempting to connect to QLog until it succeeds. If the connection gets lost it
		 * will start attempting to connect again. 
		 */
		public function QLogOutput(ip : String = "localhost", port : uint = 6666, keepConnecting : Boolean = false) {
			_ip = ip;
			_port = port;
			_keepConnecting = keepConnecting;
			
			connect();
		}

		private function connect() : void {
			_socket = new XMLSocket();
			_socket.addEventListener(Event.CONNECT, onInitialized);
			_socket.addEventListener(IOErrorEvent.IO_ERROR, onError);			_socket.addEventListener(Event.CLOSE, onClose);			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onError);
			_socket.connect(_ip, _port);
		}

		private function onClose(event : Event) : void {
			onError(event);
		}

		// Error. Probably the QLog server is not running.
		private function onError(event : Event) : void {
			_initialized = true;
			if(_keepConnecting) {
				_timer = new Timer(3000, 1);
				_timer.addEventListener(TimerEvent.TIMER, reconnect);
				_timer.start();
			}
		}

		private function reconnect(event : TimerEvent) : void {
			_timer.removeEventListener(TimerEvent.TIMER, reconnect);
			_timer.stop();
			
			connect();
		}

		private function onInitialized(e : Event) : void {
			if(_socket.connected) {
				_socket.send("<login><name>" + _formatter.getAppName() + "</name></login>");
				
				for each (var s : String in _treeAr) _socket.send(s);
				
				_initialized = true;
			}
		}

		/**
		 * A QLog specific feature which enables you to send a xml structure to QLog. The xml is 
		 * displayed within a special tab as a navigatable tree.
		 * 
		 * @param xml the xml to display as a tree
		 */
		public function sendXmlTree(xml : XML, tabName : String = "") : void {
			var str : String = "<tree id='" + tabName + "'>" + xml + "</tree>";
			if(_socket.connected) {
				_socket.send(str);
			}
			else _treeAr.push(str);
		}

		/**
		 * @inheritDoc
		 */
		override public function log(event : LogEvent) : void {
			if(_socket.connected)
				_socket.send(buildMessage(LogLevel.getLevelOutputName(event.getLevel()), _formatter.format(event)));
		}

		private function buildMessage(level : String, msg : String) : String {
			// enable the output of xml data
			msg = msg.replace(/</g, "&lt;");			msg = msg.replace(/\>/g, "&gt;");			msg = msg.replace(/<\//g, "&lt;&#47;");
			msg = msg.replace(/\/>/g, "&#47;&gt;");
			return "<log><color>" + getColorForLevel(level) + "</color><msg><![CDATA[" + msg + "]]></msg></log>";
		}

		private function getColorForLevel(level : String) : String {
			switch(level) {
				case "GARBAGE":
					return "#999900";
				case "FATAL":
					return "#FFFF00";
				case "ERROR":
					return "#FF0000";
				case "WARN":
					return "#FFFFCC";
				case "INFO":
					return "#CCFFFF";
				case "DEBUG":
					return "#00FF00";
				case "TRACE":
					return "#FFFFFF";
				default:
					return "#FFFFFF";
			}
		}
	}
}
